﻿using System;
using System.IO;
using System.Reflection;
using System.Text;
using System.Windows.Forms;

namespace Abide.Forms
{
    public partial class ConsoleLog : Form
    {
        public TextWriter Writer
        {
            get { return writer; }
        }
        public bool FileLogging
        {
            get { return fileLogging; }
        }

        private readonly TextWriter writer;
        private Stream logStream = null;
        private StreamWriter logWriter = null;
        private bool fileLogging = false;
        private StringBuilder log;

        public ConsoleLog()
        {
            InitializeComponent();
            log = new StringBuilder();
            writer = new ConsoleLogWriter(this);
        }
        private void ConsoleLog_FormClosing(object sender, FormClosingEventArgs e)
        {
            //Hide form for user closing.
            if (e.CloseReason == CloseReason.UserClosing)
            {
                e.Cancel = true;
                Hide();
            }
        }
        private void topMostCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            //Set...
            TopMost = topMostCheckBox.Checked;
        }
        private void ConsoleLog_VisibleChanged(object sender, EventArgs e)
        {
            if(Visible)
            {
                //Write Log
                logBox.AppendText(log.ToString());
                logBox.Select(logBox.TextLength, 0);
                logBox.ScrollToCaret();
            }
            else
            {
                //Clear
                logBox.Clear();
            }
        }
        public void LogToFile()
        {
            //Create File...
            string fileName = Path.Combine(Path.GetDirectoryName(Assembly.GetCallingAssembly().CodeBase), "Logs", string.Format("{0}.txt", DateTime.Now.ToLongDateString()));

            //...
            LogToFile(fileName);
        }
        public void LogToFile(string fileName)
        {
            //...
            if (string.IsNullOrEmpty(fileName))
                fileName = Path.Combine(Application.StartupPath, "Log.txt");

            //Load File...
            logStream = new FileStream(fileName, FileMode.Append, FileAccess.Write, FileShare.Read);

            //Prepare
            logWriter = new StreamWriter(logStream, Encoding.UTF8);
            logWriter.AutoFlush = true;
            fileLogging = true;

            //Write
            Console.WriteLine("Console Log being saved to {0}", fileName);
        }
        public void CloseFileLog()
        {
            if (fileLogging)
            {
                //Set output
                Console.SetOut(writer);

                //Close
                fileLogging = false;

                //Close
                Writer.Close();
                logStream.Close();

                //Cleanup
                logStream.Dispose();
                Writer.Dispose();

                //Write
                Console.WriteLine("File logging closed.");
            }
        }
        protected override void OnHandleCreated(EventArgs e)
        {
            base.OnHandleCreated(e);
            Console.WriteLine("Console Window Handle Created");
        }

        private void Write(char value)
        {
            //Check...
            if (disableLogCheckBox.Checked)
                return;

            //Check
            if (IsHandleCreated && Visible && value != '\r')
                BeginInvoke(new MethodInvoker(delegate
                {
                    //Write Log
                    logBox.AppendText(char.ToString(value));
                    logBox.Select(logBox.TextLength, 0);
                    logBox.ScrollToCaret();
                }));
        }

        private class ConsoleLogWriter : TextWriter
        {
            public override Encoding Encoding
            {
                get { return Encoding.UTF8; }
            }

            private readonly ConsoleLog owner;

            public ConsoleLogWriter(ConsoleLog owner)
            {
                //Setup
                this.owner = owner;
            }
            public override void Write(char value)
            {
                //Base Write...
                base.Write(value);

                //Write to stream...
                if (owner.fileLogging)
                    owner.logWriter.Write(value);

                //Append
                owner.log.Append(value);

                //Write...
                owner.Write(value);
            }
        }
    }
}
